Linux学习系列

您所在的位置:网站首页 makefile 中文手册 Linux学习系列

Linux学习系列

2024-06-30 21:51| 来源: 网络整理| 查看: 265

Linux学习系列目录

Linux学习系列—Makefile

文章目录 Linux学习系列目录前言一、概述1.关于程序的编译和链接 二、Makefile介绍1.Makefile规则2.make是如何工作的3.Makefile中使用变量3.让make自动推导4.另类风格的Makefiles5.清空目标文件的规则6.Makefile中有什么7.Makefile的文件名8.引用其他的Makefile9.环境变量MAKEFILES9.make的工作方式 三、书写规则1.规则的语法2.在规则中使用通配符3.文件搜寻4.伪目标4.多目标4.静态模式4.自动生成依赖关系 四、书写命令1.显示命令2.命令执行3.命令出错4.嵌套执行make5.定义命令包 五、使用变量1.变量的基础2.变量中的变量3.变量高级语法4.追加变量值5.override指示符6.多行变量7.环境变量(CFLAGS,目前还未熟悉透)8.目标变量9.模式变量 六、使用条件判断1.示例2.语法 七、使用函数1.函数调用的语法2.字符串处理函数3.文件名操作函数4.foreach函数5.if函数6.call函数7.origin函数8.shell函数 八、make的运行1.重要的参数 总结

前言

本篇文档的参考书籍如下: 1)《GNU make》中文手册,徐海兵翻译; 2)《跟我一起写Makefile》,陈皓。 《GNU make》中文手册是官方GUN make文档的翻译版本,可以作为查找资料使用;陈皓编写的《跟我一起写Makefile》篇幅相对于上一版篇幅较少,由于最近项目需要涉及到Linux应用的开发,以提高工作效率为导向,直接开始学习《跟我一起写Makefile》,下述的文档是记录个人觉得这篇著作中比较重要的部分、个人理解以及实践。

一、概述

大多数IDE工具都在内部集成了make命令,可以一键编译工程;但是在Linux环境下编译工程还是得手写Makefile(也可以使用cmake工具生成Makefile,然后make编译;需要学习《CMakeLists》文件的编写规则),鉴于此,作者以看懂、手写Makefile的目的开启Makefile文档的学习。 Makefile制定了整个工程的编译规则,用户只需要在命令行输入make指令就可使make自动读入makefile,根据其内容完成工程的编译。Makefile和Shell脚本比较像,因为规则的命令是调用shell执行操作系统的命令,因此在命令处可通过shell编程实现复杂的逻辑控制。 Makefile的本质:在文件的依赖关系上做文章。

1.关于程序的编译和链接

通常口头描述的编译是两个过程的集合:编译+链接

编译用于将源文件生成中间文件,在Linux中是.o后缀的文件,一般一个源文件对应一个中间文件;链接用于将中间文件合并,生成可执行文件。

关于编译、链接、库等知识,有兴趣的可以阅读《程序员的自我修养:链接,装载与库》,后续作者也将学习这本书籍的知识,文章将存入Linux学习系列。

二、Makefile介绍 1.Makefile规则 targets...:prerequsites... [Tab]Command targets…是一个或多个目标文件,targets也可以是一个标签(如果下面有命令,可看作伪目标);prerequsites是生成该target 所依赖的文件;[Tab]是Table键,只有这个放在行首,make才会将这一行的后续内容看作命令。Command是targets 要执行的命令(任意的shell 命令)

**PS:**所以像写好一个Makefile,还缺少一个元素:Shell编程(目前准备学习《鸟哥的Linux私房菜》中的Chapter13学习Shell Scripts)+《Linux命令行与Shell脚本编程大全》

规则描述如下:

如果这个工程没有编译过,那么我们的所有c 文件都要编译并被链接; 如果这个工程的某几个c 文件被修改,那么我们只编译被修改的c 文件,并链接目标程序; 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的c 文件,并链接目标程序 #'\'是换行符 edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c #对于没有依赖文件的目标文件的执行,命令行处需要在make命令之后声明目标文件的名称 clean : rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 2.make是如何工作的 make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make 就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make 根本不理。make 只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。 意思就是当make找到依赖的源头之后就不干了,接下来就该Shell开秀了。 3.Makefile中使用变量

Makefile中的变量C语言中的宏,会展开。

#使用变量指定文件列表,make命令读入Makefile时会将变量直接展开 objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o #'\'是换行符 edit : ${objects} cc -o edit ${objects} main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c #对于没有依赖文件的目标文件的执行,命令行处需要在make命令之后声明目标文件的名称 clean : rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 3.让make自动推导

GNU 的make 很强大,它可以自动推导文件以及文件依赖关系后面的命令。 EX:只要make 看到一个.o 文件,它就会自动的把.c文件加在依赖关系中,如果make 找到一个 whatever.o ,那么whatever.c 就会是whatever.o的依赖文件。并且cc -c whatever.c 也会被推导 出来。 这样代码块就会被简化成下述代码。

objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : rm edit $(objects)

PS:make自动推导的命令使用的cc编译器,对于不适用这个编译器的人来说需要手动添加命令。

4.另类风格的Makefiles

由于有多个中间文件(.o)的依赖文件是相同的头文件,因此可以将相同头文件作为依赖的目标合并成一个多目标规则,见下述代码。

objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h .PHONY : clean clean : rm edit $(objects) 5.清空目标文件的规则 #.PHONY将clean声明为伪目标:防止当目录中存在clean时,它作为目标文件一直是新的, #其规则定义中的命令就不会执行 .PHONY: clean clean: rm edit $(objects) 6.Makefile中有什么

显示规则、隐含规则、变量定义、文件指示、注释

显式规则:显式规则说明了如何生成一个或多个目标文件。这是由Makefile 的书写者明显指出要生成的文件、文件的依赖文件和生成的命令。

隐含规则:由于我们的make 有自动推导的功能,所以隐含的规则可以让我们比较简略地书写Makefile,这是由make 所支持的。

文件指示:其包括了三个部分,一个是在一个Makefile 中引用另一个Makefile,就像C 语言中的include 一样;另一个是指根据某些情况指定Makefile 中的有效部分,就像C 语言中的预编译#if一样;还有就是定义一个多行的命令。

7.Makefile的文件名

默认情况:make会在当前目录下按照如下优先级去寻找Makefile:GNUmakefile>makefile>Makefile

指定情况:Shell在执行make命令时,通过-f选项或–file选项,将后续的文件指定为Makefile,供make命令读取。

8.引用其他的Makefile

在Makefile 使用include 关键字可以把别的Makefile 包含进来,这很像C 语言的#include ,被 包含的文件会原模原样的放在当前文件的包含位置。

include foo.make *.mk $(bar)

make 命令开始时,会找寻include 所指出的其它Makefile,并把其内容安置在当前的位置。就好 像C/C++ 的#include 指令一样。如果文件都没有指定绝对路径或是相对路径的话,make 会在当前目录下首先寻找,如果当前目录下没有找到,那么,make 还会在下面的几个目录下找:

如果make 执行时,有-I 或–include-dir 参数,那么make 就会在这个参数所指定的目录下去 寻找。如果目录/include (一般是:/usr/local/bin 或/usr/include )存在的话,make 也 会去找。

如果有文件没有找到的话,make 会生成一条警告信息,但不会马上出现致命错误。 如果你想让make 不理那些无法读取的文件,而继续执行,你可以在include 前加一个减号“-”。

9.环境变量MAKEFILES

建议不要使用:在这里提这个事,只是为了告诉大家,也许有时候你的Makefile 出现了怪事,那么你可以看看当前环境中有没有定义这个变量。

9.make的工作方式

执行步骤如下:

#第一阶段 1. 读入所有的Makefile。 2. 读入被include 的其它Makefile。 3. 初始化文件中的变量。 4. 推导隐含规则,并分析所有规则。 5. 为所有的目标文件创建依赖关系链。 #第二阶段 6. 根据依赖关系,决定哪些目标要重新生成。 7. 执行生成命令。

读取所有Makefile,初始化变量,展开变量,建立目标的依赖关系链,执行shell生成命令。

三、书写规则

规则=依赖关系+生成目标的方法 第一条规则的目标=最终的目标

1.规则的语法 #command要么放在依赖关系后,但以;开始 #command要么单独放在一行,以【tab】键开始 targets : prerequisites ; command command ...

一般来说,make 会以UNIX 的标准Shell,也就是/bin/sh 来执行命令。

2.在规则中使用通配符 make 支持三个通配符:* ? ~如果我们的文件名中有通配符,如:* ,那么可以用转义字符\ ,如* 来表示真实的* 字符 #通配符的应用举例 ###/* case1:用于规则中 ###*/ print: *.c lpr -p $? touch print ###/* case2.1:用于变量中,此时通配符不会展开,只是作为文本字符串的一个字符 ###*/ objects = *.o ###/* case2.2:要想让通配符在变量中展开,可以按照下例进行书写 ###*/ objects:= $(patsubst %.c, %.o, $(wildcard *.c)) foo: $(objects) gcc -o $@ $^ 3.文件搜寻 ###/* case1,若不声明VPATH变量(不是环境变量)或者vpath关键字,make会在当前工作目录下找目标文件 和依赖文件 ###*/ ###/* case2,定义VPATH变量时,make在当前工作目录下找不到目标文件和依赖文件时会到VPATH变量 定义的目录下去寻找 ###*/ #make会到src目录下,../headers目录下寻找文件 VPATH = src:../headers ###/* case3,定义vpath关键字时,make在当前工作目录下找不到目标文件和依赖文件时会到vpath关键字 定义的目录下去寻找 ###*/ #make找寻.c文件时会先到foo目录下,再到bar目录,最后到blish目录下找文件 #make找寻任意文件时会去blish目录下 vpath %.c foo:bar vpath % blish 4.伪目标 伪目标一般没有依赖文件,如clean:伪目标包含依赖文件时,可以用于给多目标编写规则 ###/* 可以将所有不相关的目标文件写在一个Makefile文件中 ###*/ all : prog1 prog2 prog3 #使用.PHONY显示声明伪目标,若不书写,make会根据隐含规则推导 .PHONY : all prog1 : prog1.o utils.o cc -o prog1 prog1.o utils.o prog2 : prog2.o cc -o prog2 prog2.o prog3 : prog3.o sort.o utils.o cc -o prog3 prog3.o sort.o utils.o 伪目标也可以作为依赖文件,和C语言中的程序调用相似 .PHONY : cleanall cleanobj cleandiff cleanall : cleanobj cleandiff rm program cleanobj : rm *.o cleandiff : rm *.diff 4.多目标 有可能我们的多个目标同时依赖于一个文件,并且其生成的命令大体类似。于是我们就能把其合并起来; @ 表示目标的集合,就像一个数组, @表示目标的集合,就像一个数组, @表示目标的集合,就像一个数组,@依次取出目标,并执于命令。$@提供了一种对多目标列表中的不同目标文件执行不同命令的可能。 bigoutput littleoutput : text.g generate text.g -$(subst output,,$@) > $@ 等价于 bigoutput : text.g generate text.g -big > bigoutput littleoutput : text.g generate text.g -little > littleoutput 4.静态模式 静态模式的语法如下 ###/* 下述创建的规则为:目标文件列表中 的 模式的目标文件,其依赖 文件为 的模式的依赖文件 ###*/ : : 举例如下 files = foo.elc bar.o lose.o $(filter %.o,$(files)): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ $(filter %.elc,$(files)): %.elc: %.el emacs -f batch-byte-compile $< 等价于 files = foo.elc bar.o lose.o all: $(objects) foo.o : foo.c $(CC) -c $(CFLAGS) foo.c -o foo.o bar.o : bar.c $(CC) -c $(CFLAGS) bar.c -o bar.o foo.elc : foo.el emacs -f batch-byte-compile $< 4.自动生成依赖关系

由于源文件会包含头文件,因此当头文件改变时,目标文件得更新,那么规则中目标文件的依赖文件列表中必须包含头文件,这样就考验程序员是否能罗列清除头文件。 为了解决这个困扰,选择通过include的方式,将依赖关系直接包含进Makefile中,这样make命令在读取Makefile时,就知道了所有的依赖关系(头文件!!)。

本质:大多数的C/C++ 编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。提醒:如果你使用GNU 的C/C++ 编译器,得用-MM 参数,不然,-M参数会把一些标准库的头文件也包含进来。 dep_files := $(foreach f, $(objs), .$(f).d) #因为后续变量会生成新的.d文件,所以当这次make生成.d文件时,在下次make执行时会包含进来 dep_files := $(wildcard $(dep_files)) # 把依赖文件包含进来,第一次make时,没有.d不会执行,后续make有.d就会执行了。 ifneq ($(dep_files),) include $(dep_files) endif #将生成的依赖关系放到.d文件中 %.o : %.c gcc -Wp,-MD,[email protected] -c -o $@ $< 四、书写命令 1.显示命令

make会把其要执行的命令行在命令执行前输出到屏幕上。

当命令行前有@字符,那么这个命令将不被make显示出来make -n或–just-print是只显示命令,但不会执行命令;可以用来观察命令的执行顺序make -s或–silent或–quiet是全面禁止命令的显示。 2.命令执行 如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令 (这是因为,各个命令是独立的在不同的shell中执行,只有加;分隔才能在一个shell中执行,这样上条命令的结果会应用在下一条命令中)make 一般是使用环境变量SHELL 中所定义的系统Shell 来执行命令 3.命令出错 可在命令行前加一个减号-,将忽略这个命令是否执行成功。make -i或–ignore-errors,会忽略Makefile中所有命令的错误make -k或–keep-going,会停止执行出错的规则,但是执行其他规则 4.嵌套执行make

在大工程中,会将不同的模块、不同功能的源文件放在不同的目录,这时,可以为每个目录编写Makefile,使每个Makefile文件变得简洁,利于维护,而且利于模块编译和分段编译。

subsystem: cd subdir && $(MAKE) 等价于 $(MAKE) -C subdir

Makefile中变量的传递:

export#后不接任何标识符表示传递所有变量至下级Makefile并覆盖 export#传递变量至下级Makefile并覆盖 unexport#不传递变量至下级Makefile

系统变量SHELL与系统变量MAKEFLAGS的值总是要传递至下级Makefile MAKEFLAGS是执行make命令或者设置的参数:

-w 或是 --print-directory参数会在 make 的过程中输出一些信息,让你看到目前的工作目录;参数中有 -s(–slient)或是 --no-print-directory ,那么, -w 总是失效的;-C , -f , -h, -o 和 -W这些参数不会传递至下级Makefile。

若不想往下层传递MAKEFLAGS,见下例:

subsystem: #MAKEFLAGS直接设置为空 cd subdir && $(MAKE) MAKEFLAGS= 5.定义命令包

命令包命令的集合,语法为:以 define 开始,以 endef 结束定义的变量,这个变量就是命令包的接口。

#定义命令包run-yacc define run-yacc yacc $(firstword $^) mv y.tab.c $@ endef #执行命令包run-yacc foo.c : foo.y $(run-yacc) 五、使用变量 Makefile中的变量与C/C++中的宏相似(体现在展开上),但是可以更改其值变量是大小写敏感的 1.变量的基础 文本替换建议使用时给变量添加括号 2.变量中的变量 定义变量时,可以使用其他变量来构造值

a、延时变量 =

foo = $(bar) bar = $(ugh) ugh = Huh? all: echo $(foo) 将会输出Huh? 用其他变量来构造变量的值时,其他变量可以在后面定义:延时变量,在使用时才展开

b、即时变量 :=

y := $(x) bar x := foo #y的值为bar

c、系统变量“MAKELEVEL”:这个变量会记录了我们的当前Makefile 的调用层数。

d、值是一个空格的变量

nullstring := space := $(nullstring) # end of the line #之前有个空格,#代表变量定义的结束,$(变量)代表变量的开始

e、首次使用可定义操作符?=

FOO ?= bar 等价于 ifeq ($(origin FOO), undefined) FOO = bar endif 3.变量高级语法

a、变量值的替换

$(var:a=b) 把变量var中的结尾字符串a都换成字符串b 可以使用之前的章节“静态模式” foo := a.o b.o c.o bar := $(foo : %.o : %.c)

b、把变量的值再当成变量

x = y y = z a := $($(x)) $(x)的值为y,再把y当作变量,使用$(y)获得值z 4.追加变量值 objects = main.o foo.o bar.o utils.o objects += another.o 等价于 objects = main.o foo.o bar.o utils.o objects := $(objects) another.o +=变成:=是因为,若不这样,就会使make递归扩展objects,所以make会自动将其 转换成:= 5.override指示符

Makefile中通过:=、+=、=定义的变量都可以通过命令行重新定义此变量的值,如果不想让命令行改变此变量值或者想对原来的值做追加操作,可以通过override实现此功能。

:=/=/+=不使用override test_data = "US" I_print: @echo $(test_data) shell中执行make I_print test_data=better,显示的结果是better; 使用make I_print,是因为得给make命令赋予目标,否则命令不执行 :=/=使用override override test_data = "US" I_print: @echo $(test_data) shell中执行make I_print test_data=better,显示的结果是US; +=使用override override test_data += "US" I_print: @echo $(test_data) shell中执行make I_print test_data=better,显示的结果是better US;

在添加编译选项时,可以将公共的选项通过追加的方式定义,可以保证通过命令行添加新的编译选项,实现编译选项的叠加。

6.多行变量 define变量

define指示符后面跟的是变量的名字,重起一行定义变量的值,定义是endef关键字结束; 变量的值可以包含函数、命令、文字,或是其它变量;。因为命令需要以[Tab]键开头,所以如果你用define 定义的命令变量中没有以Tab 键开头,那么make 就不会把其认为是命令。

define objects Hello World endef Print: @echo ${objects} 执行make时,会显示Hello World,同时make命令的同时,可以修改objects变量的值 7.环境变量(CFLAGS,目前还未熟悉透) make 运行时的系统环境变量可以在make 开始运行时被载入到Makefile 文件中;如果make 命令行带入系统变量值,那么系统的环境变量的值将被覆盖;如果make 指定了“-e”参数,那么,系统环境变量将覆盖Makefile 中定义的变量;如果我们在环境变量中设置了CFLAGS 环境变量,那么我们就可以在所有的Makefile 中使用这个变量了;如果Makefile 中定义了CFLAGS,那么则会使用Makefile 中的这个变量,如果没有定义则使用系统环境变量的值;当make 嵌套调用时,上层Makefile 中定义的变量会以系统环境变量的方式传递到下层Makefile 中。定义在文件中的变量,如果要向下层Makefile 传递,则需要使用exprot 关键字来声明。 8.目标变量

在Makefile 中定义的变量都是“全局变量”,在整个文件,我们都可以访问这些变量,“自动化变量”除外。 可以为某个目标设置局部变量,当局部变量与全局变量标识符相同时,采用局部变量处理规则内部,语法与作用如下:

prog : CFLAGS = -g prog : prog.o foo.o bar.o $(CC) $(CFLAGS) prog.o foo.o bar.o prog.o : prog.c $(CC) $(CFLAGS) prog.c foo.o : foo.c $(CC) $(CFLAGS) foo.c bar.o : bar.c $(CC) $(CFLAGS) bar.c 为prog指定了局部变量CFLAGS的值为-g,在prog这个目标的所有规则中,CFLAGS的值保持不变。 9.模式变量

生产目标变量:我们可以给定一种“模式”,可以把变量定义在符合这种模式的所有目标上。

%.o : CFLAGS = -O 会把所有带.o后缀文件的目标变量CFLAGS参数设置为-o 六、使用条件判断

使用条件判断,可以让make 根据运行时的不同情况选择不同的执行分支。条件表达式可以是比较 变量的值,或是比较变量和常量的值。

1.示例 libs_for_gcc = -lgnu normal_libs = foo: $(objects) ifeq ($(CC),gcc) $(CC) -o foo $(objects) $(libs_for_gcc) else $(CC) -o foo $(objects) $(normal_libs) endif 判断$(CC) 变量是否gcc 2.语法 1)ifeq (, ) 2)ifneq (, ) 3)ifdef #ifdef 只是测试一个变量是否有值 4)ifndef PS:不要把自动化变量放到条件表达式中,因为自动化变量是在运行时才有的。 七、使用函数 1.函数调用的语法 $( ) 函数名和参数之间以“空格”分隔; 参数间以逗号, 分隔。 2.字符串处理函数 $(subst ,,) 把字串 中的 字符串替换成 $(patsubst ,,) 查找 中的单词是否符合模式 ,如果匹配的话,则以 替换。 $(strip ) 去掉 字串中开头和结尾的空字符;将字符串中间连续的空格缩减为1个 $(findstring ,) 在字串 中查找 字串。 $(filter ,) 以 模式过滤 字符串中的单词,保留符合模式 的单词。可以有多个模式。 $(filter-out ,) 以 模式过滤 字符串中的单词,去除符合模式 的单词。可以有多个模式。 $(sort ) 给字符串 中的单词排序(升序)。 $(word ,) 取字符串 中第 个单词。(从一开始); 如果 比 中的单词数要大,那么返回空字符串。 $(wordlist ,,) 从字符串 中取从 开始到 的单词串。 和 是一个数字。 如果 比 中的单词数要大,那么返回空字符串。如果 大于 的单词数, 那么返回从 开始,到 结束的单词串。 $(words ) 统计 中字符串中的单词个数。 $(firstword ) 取字符串 中的第一个单词。 3.文件名操作函数 $(dir ) 从文件名序列 中取出目录部分。目录部分是指最后一个反斜杠(/ )之前的部分。 如果没有反斜杠,那么返回./ 。 $(dir src/foo.c hacks) 返回值是src/ ./ $(notdir ) 从文件名序列 中取出非目录部分。非目录部分是指最後一个反斜杠(/ )之后的部分。 $(suffix ) 从文件名序列 中取出各个文件名的后缀。 $(basename ) 从文件名序列 中取出各个文件名的前缀部分。 $(addsuffix ,) 把后缀 加到 中的每个单词后面。 $(addprefix ,) 把前缀 加到 中的每个单词后面。 $(join ,) 把 中的单词对应地加到 的单词后面。 示例:$(join aaa bbb , 111 222 333) 返回值是aaa111 bbb222 333 。 4.foreach函数

foreach 函数是用来做循环用的;

$(foreach ,,)

这个函数的意思是,把参数(list)中的单词逐一取出放到参数(variable) 所指定的变量中,然后再执行(text) 所包含的表达式。循环过程中,(text) 的所返回的每个符串会以空格分隔,最后当整个循环结束时,(text) 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach 函数的返回值。

names := a b c d files := $(foreach n,$(names),$(n).o) 返回为a.o b.o c.o d.o 5.if函数 $(if ,) $(if ,,)

如果(condition) 为真(非空字符串),那个(then-part)会是整个函数的返回值,如果(condition) 为假(空字符串),那么(else-part) 会是整个函数的返回值,此时如果(else-part) 没有被定义,那么,整个函数返回空字串。

6.call函数 $(call ,,,...,) 当make 执行这个函数时, 参数中的变量,如$(1) 、$(2) 等,会被参数 、 、 依次取代 7.origin函数

origin 函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的.

$(origin ) 8.shell函数

执行/bash/shell处理,将处理结果作为函数的返回值

contents := $(shell cat foo) 八、make的运行 1.重要的参数 -n, --just-print, --dry-run, --recon 不执行参数,这些参数只是打印命令,不管目标是否更新,把 规则和连带规则下的命令打印出来,但不执行,这些参数对于我们调试makefile 很有用处。-W file, --what-if=file, --assume-new=file, --new-file=file 这个参数需要指定一个文件。一般是源文件(或依赖文件),Make会根据规则推导来运行依赖于这个文件的命令,一般来说,可以和“-n”参数一同使用,来查看这个依赖文件所发生的规则命令。-C dir, --directory=dir 指定读取makefile 的目录。-d 相当于“–debug=a”,输出所有调试信息。 总结

看完了,其中关于隐含规则等知识只理解了其中部分的模式规则,有需要的可以继续学习。 学习完结之后,开始做联系,由于编程习惯是各个模块单独存放在一个目录,因此将做一个关于多目录的Makefile实例进行联系,参考文档如下: 多目录Makefile实例



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3